try 
{
model={};
// информация о текущем пользователе
model.me={};
ctrl={};

/// ////////////////////////////
/// ////////////////////////////
/// ////////////////////////////
function setCookie(name, value, expires, path, domain, secure) {
  if (!name || !value) return false;
  var str = name + '=' + encodeURIComponent(value);
  
  if (expires) str += '; expires=' + expires.toGMTString();
  if (path)    str += '; path=' + path;
  if (domain)  str += '; domain=' + domain;
  if (secure)  str += '; secure';
  
  document.cookie = str;
  return true;
}


function getCookie(name) {
  var pattern = "(?:; )?" + name + "=([^;]*);?";
  var regexp  = new RegExp(pattern);
  
  if (regexp.test(document.cookie))
  return decodeURIComponent(RegExp["$1"]);
  
  return false;
}

function deleteCookie(name, path, domain) {
  setCookie(name, null, new Date(0), path, domain);
  return true;
}

function isLocalStorageAvailable() 
{
  try 
  {
    return 'localStorage' in window && window['localStorage'] !== null;
  } 
  catch (e) 
  {
    return false;
  }
}

function parseURIQuery(query) 
{
  var data = {};
  if (!query) return data;
  
  var pair = ( data.substring(1) ).split('&');
  
  for(var i = 0; i < pair.length; i ++) 
  {
    var param = pair[i].split('=');
    data[ param[0] ] = decodeURIComponent(param[1]);
  }
  return data;
}

/// ////////////////////////////
/// ////////////////////////////
/// ////////////////////////////

acc = {};

acc.me = 
{
  isLoaded: false, 
  query: false,
  callback: [],
  
  fire: function()
  {
    for (var i = 0; i < this.callback.length; ++i )
      this.callback[i](model.me);
    this.callback = [];
  },
  
  get: function(callback) { try {
    
    if (callback)
      this.callback.push(callback);
    
    if (this.isLoaded)  
    {
      this.fire();
    }
    else if (!this.query)
    {
      this.query = true;
      queryFacebook("me", "acc.me.loaded");
    }
  } catch(e){alert(e.message)}},
  
  loaded: function(me)
  {
    model.me.id = me.id;
    model.me.name = me.name;
    queryFacebook("me/picture", "acc.me.loadedPicture");
  },
  
  loadedPicture: function(picture)
  {
    this.isLoaded = true;
    this.query = false;

    model.me.picture = picture;
    this.fire();
  }
};

function AccFriendLoader(id, owner)
{
  this.owner = owner;
  this.id = id;
  this.isLoaded = false;
  this.query = false;
  this.callbacks = [];

  this.fire = function()
  {
    for (var i = 0; i < this.callbacks.length; ++i )
    {
      try
      {
        this.callbacks[i](model.me.friends[this.id]);
      }
      catch(e)
      {
        alert("fire: " + e.message);
      }
    }
    this.callbacks = [];
  }
  
  this.attach = function(callback) { try {
    
    if (callback)
      this.callbacks.push(callback);
    
  } catch(e){alert(e.message)}}
  
  this.load = function() { try {

    if (this.isLoaded)  
    {
      this.fire();
    }
    else if (!this.query)
    {
      this.query = true;
      // alert( "queryFacebook " + acc.friends.friendsLoaders[this.id].loaded );
      queryFacebook(this.id, "acc.friends.friendsLoaders["+this.id+"].loaded");
    }
  
  } catch(e){alert(e.message)}}
  
  this.get = function(callback) { try {

    if (callback)
      this.callbacks.push(callback);
    
    if (this.isLoaded)  
    {
      this.fire();
    }
    else if (!this.query)
    {
      this.query = true;
      queryFacebook(this.id, "acc.friends.friendsLoaders["+this.id+"].loaded");
    }
    
  } catch(e){alert(e.message)}}
  
   this.dispose = function(callback) { try {
    
    for (var i = 0; i < this.callbacks.length; ++i )
    {
      if ( this.callbacks[i] == callback)
        this.callbacks[i]=null;
    }
    
  } catch(e){alert(e.message)}},
 
  
  this.loaded = function(user)
  {
    model.me.friends[this.id].id = user.id;
    model.me.friends[this.id].name = user.name;
    queryFacebook(this.id + "/picture", "acc.friends.friendsLoaders["+this.id+"].loadedPicture");
  }
  
  this.loadedPicture = function(picture) { try {

    this.isLoaded = true;
    this.query = false;
  
    model.me.friends[this.id].picture = picture;
    this.fire();
    this.owner.processWaitList();
  } catch(e){alert("loadedPicture: " + e.message)}}

}

acc.friends =
{
  isFriendListLoaded: false,
  friendListQuery: false,
  waitList: [],
  callbacks: [],
  friendsLoaders: {},
  
  fire: function()
  {
    for (var i = 0; i < this.callbacks.length; ++i )
      if ( this.callbacks[i] )
        this.callbacks[i](model.me.friends);
    this.callbacks = [];
  },

  get: function(callback) { try {

    if (callback)
      this.callbacks.push(callback);
    
    if (this.isFriendListLoaded)  
    {
      this.fire();
    }
    else if (!this.friendListQuery)
    {
      this.friendListQuery = true;
      queryFacebook("me/friends", "acc.friends.loaded");
    }
  } catch(e){alert(e.message)}},
  
  dispose: function(callback) { try {
    
    for (var i = 0; i < this.callbacks.length; ++i )
    {
      if ( this.callbacks[i] == callback)
        this.callbacks[i]=null;
    }
    
  } catch(e){alert(e.message)}},
  
  processWaitList: function() { try {
  
    // alert(this.waitList.length);
    if (this.waitList.length==0)
      return;
    
    while  (this.waitList.length > 0)
      this.friendsLoaders[this.waitList.pop()].load();
    
  } catch(e){alert(e.message)}},
  
  getFriend: function(id, callback) { try {
    
    if ( !this.friendsLoaders[id] )
      this.friendsLoaders[id] = new AccFriendLoader(id, this);
    
    if ( !this.isFriendListLoaded /*|| this.waitList.length!=0*/ )
    {
      this.waitList.push(id);
      this.friendsLoaders[id].attach(callback);
    }
    else
      this.friendsLoaders[id].get(callback);
    
  } catch(e){alert(e.message)}},
  
  loaded: function(data)
  {
    this.isFriendListLoaded = true;
    this.friendListQuery = false;
    
    if ( !model.me.friends )
      model.me.friends = {};
    for ( var i=0; i < data.data.length; ++i)
    {
      var fr = data.data[i];
      if (!model.me.friends[ fr.id ])
        model.me.friends[ fr.id ] = {};
      model.me.friends[ fr.id ].id = fr.id;
      model.me.friends[ fr.id ].name = fr.name;
    }
    
    this.fire();
    this.processWaitList();
  }
  
};

function MePublisher()
{
  
  this.publish = function() { try {
    var me = { id: model.me.id, name:model.me.name, picture:model.me.picture };
    
    comet.publish(
      {
        action: "update",
        channel: "faceonline.face."+model.me.id,
        limit:1,
        lifetime:3600*24*7,
        content: me
      }
    );
  } catch(e){ alert(e.message) } }
  
  this.ready = function()
  {
    // TODO: опубликовать еще в канал что на online
    this.publish();
  }
  
  var self = this;
  acc.me.get(function() { self.ready() } );
}

/*
ctrl.me.get = function( callback )
{
  if ( callback )
  {
    if ( !this.callback ) 
      this.callback=[];
    this.callback.push( callback )
  }
  
  if (this.isLoaded)
  {
    if ( callback) 
      callback( model.me );
  }
  else
  {
    
  }
  return model.me;
}
*/








function MeController1( loader )
{
  var id = null;
  if ( isLocalStorageAvailable()  )
  {
    id = localStorage.getItem('id');
    if ( localStorage.getItem('me-'+id) )
      model.me = JSON.parse(localStorage.getItem('me-'+id));
  }
  else
    id = getCookie("id");
    
  
  if ( id )
  {
    model.me.id = id;
    var mechannel = "faceonline.me."+id;
    var self = this;
    //alert(mechannel);
    comet.subscribe( mechannel, function(messages){ self.updateChannel(messages); } );
    comet.open( { channel:mechannel, cursor: 1, min_size: 1, max_size: 1000 } );
  }
  
  this.subscribers = [];
  
  this.subscribe = function ( target )
  {
    this.subscribers.push( target );
    target.update();
  }

  this.fire = function ()
  {
    // alert("this.fire = " + this.subscribers.length);
    for (var i = 0; i < this.subscribers.length; i++)
        this.subscribers[i].update();
  }

  this.updateChannel = function(messages)
  {
    try
    {
      
      var user = messages.content;
      // alert(JSON.stringify(user));
      for ( var prop in user ) if ( user.hasOwnProperty(prop) ) 
      {
        model.me[prop] = user[prop];
      }

      //if ( model.me.name ) model.me.name += "-2";
      this.fire();
    }
    catch(e)
    {
      alert(e.message)
    }
  }
  
  this.updateMe = function(user)
  {
    if ( user.id && model.me.id && user.id != model.me.id )
    {
      var mechannel = "faceonline.me."+user.id;
      comet.describe( mechannel );
      comet.close( { channel:mechannel } );
    }
      
    if ( user.id && !model.me.id )
    {
      model.me.id = user.id;
      var mechannel = "faceonline.me."+user.id;
      
      var self = this;
      comet.subscribe( mechannel, function(messages){ self.updateChannel(messages); } );
      comet.open( { channel:mechannel, cursor: 1, min_size: 1, max_size: 1000 } );
      
    }
    
    
    for ( var prop in user ) if ( user.hasOwnProperty(prop) ) 
    {
      model.me[prop] = user[prop];
    }
    
    if ( !model.me.id )
      return;
    
    //if ( model.me.name ) model.me.name += "-1";
    
    if ( isLocalStorageAvailable()  )
    {
      localStorage.setItem("id", model.me.id);
      localStorage.setItem('me-'+model.me.id, JSON.stringify(model.me) );
    }
    else
    {
      setCookie("id", model.me.id);
    }
    
    var mechannel = "faceonline.me." + model.me.id;
    //alert(model.me.name+model.me.picture);
    if (  model.me.picture )
      comet.simplePublish( mechannel, model.me );
  }
  
  
  this.loader = loader;
  var self = this;
  this.loader.load2( function(user) { self.updateMe(user); } );
};

function FriendController(id)
{
  this.id = id;
  this.loader = friendListLoader.friendLoader(id);
  this.callbacks = [];
  
  this.loaded = function( user )
  {
    model.me.friends[user.id] = user;
    this.fire();
  };
  
  this.subscribe = function( callback )
  {
    this.callbacks.push(callback);
    callback();
  };
  
  this.fire = function ()
  {
    for (var i = 0; i < this.callbacks.length; i++)
        this.callbacks[i]();
  };
  
  var self = this;
  this.loader.load( function(user){ self.loaded(user); } );
  
};

function FriendListController()
{
  try
  {
    
  model.me.friends={};
  this.me = model.me;
  
  // Контроллеры для каждого френда
  this.friends = model.me.friends;
  
  this.callbacks = [];
  
  this.subscribe = function( callback )
  {
     this.callbacks.push(callback);
     callback();
  };
  
  this.fire = function ()
  {
    for (var i = 0; i < this.callbacks.length; i++)
        this.callbacks[i]();
  };
  
  this.loaded = function(friendList) { try{
    
    for (var i=0; i < friendList.length; ++i)
    {
      model.me.friends[ friendList[i].id ] = friendList[i];
    }
    /*
    this.friends = friendList;
    alert(this.friends);
    alert(model.me.friends);
    */
    //alert('loaded');
    this.fire();
    
  } catch(e){alert(e.message);}} ;
  
  this.getFriend = function(id)
  {
    if ( !this.friends[id] ) 
      this.friends[id] = new FriendController(id);
    return this.friends[id];
  }
  
  this.getAllFriends = function()
  {
    for (var i=0; i < model.me.friends.length; ++i)
    {
      var id = model.me.friends[i].id;
      if ( !this.friends[id] ) 
        this.friends[id] = new FriendController(id);
      return this.friends;
    }
    
  }
  
  var self = this;
  friendListLoader.subscribe( function(friendList){ self.loaded(friendList); } )
  friendListLoader.load();
    
  }
  catch(e)
  {
    alert(e.message);
  }
};

function Launcher()
{
  this.apps = {};
  
  this.callbacks = [];
  
  this.subscribe = function( callback )
  {
     this.callbacks.push(callback);
  };
  
  this.fire = function (app)
  {
    for (var i = 0; i < this.callbacks.length; i++)
        this.callbacks[i](app);
  };

  
  this.registry = function(name, url)
  {
    if ( !this.apps[name] )
      this.apps[name] = {};
    this.apps[name].name = name;
    this.apps[name].url = url;
    
  }
  
  this.exec = function(name, params)
  {
    UnSelectMenu();
    this.apps[name].params = params;
    this.fire( this.apps[name] );
  }

  this.execCommon = function(name, params)
  {
    this.apps[name].params = params;
    this.fire( this.apps[name] );
  }

};

function Notifier_callback(message)
{
  notifier.fire(message);
}

function Notifier()
{
  // Пописчики ( если есть то сообщение из списка удаляются )
  this.subscribers = {};

  /*
  if ( me && me.id ) this.channelName = "faceonline.notifier."+me.id;
  else this.channelName = "";
  */
 
  
  this.update = function ()
  {
    
    /*
    if ( this.channelName )
    {
      comet.describe(this.channelName, Notifier_callback);
      comet.close( this.channelName );
    }
    
    if ( model.me && model.me.id ) this.channelName = "faceonline.notifier." + model.me.id;
    else this.channelName = "";
    
    if ( this.channelName )
    {
      comet.subscribe( this.channelName, Notifier_callback );
      comet.open( { channel:this.channelName } );
    }
    */
    
    // alert(this.channelName)
  }
  
  //ctrl.me.subscribe(this);
}


function initialize()
{
  
  comet = new Comet(-1,"test");
  comet.create();
  //ctrl.me = new MeController( new MeLoaderFacebook() );
  // ctrl.friends = new FriendListController();
  launcher = new Launcher();
  //ctrl.notifier = new Notifier();
  
  launcher.registry("friend-list", "friend-list.html");
  launcher.registry("private-chat", "instant-chat.html");
  launcher.registry("whosonline", "whosonline.html");
  launcher.registry("siteonline", "siteonline.html");
  
  mePublisher = new MePublisher();
  
  fo = {}
  fo.model = model;
  fo.comet = comet;
  fo.ctrl = ctrl;
  fo.launcher = launcher;
  //fo.notifier = notifier;
  
  //new MeLoaderFacebook();
  //__meLoaderFacebook.load();
}

}
catch(e)
{
  alert(e.message);
}
